package com.qingzhuge.context;

import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;

/**
 * @author : zero.xiao
 * @description :  Spring Context 工具类
 * @date :2018/6/14 0014 下午 17:31
 * @since : 1.0.0
 * @modified :
 */
@Slf4j
@Component
@Lazy(false)
public class SpringContext implements ApplicationContextAware, DisposableBean {
	private static final Map<String, Object> SERVICE_MAP = Maps.newHashMap();

	@Autowired
	private static List<BaseRpcContext> rpcContexts;

	private static ApplicationContext applicationContext;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		SpringContext.applicationContext = applicationContext;
	}

	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	public static Object getBean(String name) {
		if (null == applicationContext) {
			return null;
		}
		return applicationContext.getBean(name);
	}
	public static <T> T getBean(String name,Class<T> clazz) {
		if (null == applicationContext) {
			return null;
		}
		return applicationContext.getBean(name,clazz);
	}

	public static <T> T getBean(Class<T> clz) {
		if (null == applicationContext) {
			return null;
		}
		return applicationContext.getBean(clz);
	}


	public static Class<?> getType(String name) {
		return applicationContext.getType(name);
	}

	public static String[] getBeanNamesForAnnotation(Class<? extends Annotation> aClass) {
		return applicationContext.getBeanNamesForAnnotation(aClass);
	}

	public static <A extends Annotation> A findAnnotationOnBean(String s, Class<A> aClass) throws NoSuchBeanDefinitionException {
		return applicationContext.findAnnotationOnBean(s,aClass);
	}

	public static <T> T getService(Class<T> claz) {
		T s = null;
		if (null != claz) {
			String clazName = claz.getName();
			s = (T) SERVICE_MAP.get(clazName);
			if (null == s) {
				synchronized (Object.class){
					s = (T) SERVICE_MAP.get(clazName);
					if (null == s) {
						if (null != rpcContexts && rpcContexts.size() > 0) {
							for (BaseRpcContext context : rpcContexts) {
								s = context.getService(claz);
								if (null != s) {
									SERVICE_MAP.put(clazName,s);
									break;
								}
							}
						}
					}
				}
			}
		}
		return s;
	}

	/**
	 * 发布事件
	 *
	 * @param event ApplicationEvent
	 */
	public static void publishEvent(ApplicationEvent event) {
		if (applicationContext == null) {
			return;
		}
		applicationContext.publishEvent(event);
	}

	/**
	 * 清除SpringContextHolder中的ApplicationContext为Null.
	 */
	public static void clearHolder() {
		if (log.isDebugEnabled()) {
			log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
		}
		applicationContext = null;
	}

	@Override
	public void destroy() {
		SpringContext.clearHolder();
	}
}